<?php


class CollectionItemTable extends Doctrine_Table {

    public static function getInstance() {
        return Doctrine_Core::getTable('CollectionItem');

    }

    /**
     * Fetch the search index - used for searching - but also
     * updating and refreshing the index.
     *
     * ALso registers the zend library if it hasn't already been registered
     * in the project.
     *
     * @return Zend_Search_Lucene the search object
     */
    public function getLuceneIndex() {
        ProjectConfiguration::registerZend();

        if (file_exists($index = self::getLuceneIndexFile())) {

            return Zend_Search_Lucene::open($index);
        } else {
            return Zend_Search_Lucene::create($index);
        }
    }


    /**
     * Determine the file name for the search index.
     *
     * @return string filename
     */
    static public function getLuceneIndexFile() {
        return sfConfig::get('sf_data_dir').'/searchIndex/'.sfConfig::get('sf_environment').'.index';
    }

    public function optimizeLuceneIndex() {
        $index = $this->getLuceneIndex();
        $index->optimize();
    }

    /**
     * Returns a DoctrineQuery object with the where clause set to find
     * the repositories returned from a search query request.
     *
     * @param String $queryString the query to execute
     * @return DoctrineQuery a doctrine query object to be executed (or added
     * too to return the collections from the query
     */
    public function getSearchQuery($queryString, $resultTypeLimiter) {
        $index = $this->getLuceneIndex();
        $hits  = $index->find($queryString);
        $pks = array();
        foreach ($hits as $hit) {
            $pks[] = $hit->pk;
        }
        if (count($pks) < 1) {
            return null;
        }

        $q = $this->createQuery()->whereIn('uin', $pks);
        /**
         * Archived items shouldn't even be in the search index
         * but just in case let's exclude them from the resultset
         */
        $q = $this->addNonArchivedQuery($q);
        /**
         * If the type limiter is specified add it to the where clause
         * to limit the type of collection items returned
         */
        if ($resultTypeLimiter != null) {
            $q->andWhere('collectionTypeUin = ?', $resultTypeLimiter);
        }

        return $q;
    }


    /**
     * REturns a query object with an addtional where clause to exclude
     * all archived CollectionItems - will create its own query object
     * if none is provided
     *
     * @param Doctrine_Query $q an existing Doctrine_Query or null
     * @return Doctrine_Query $q (or a new Doctrine_Query) with the where
     * clause appended
     */
    public function addNonArchivedQuery(Doctrine_Query $q = null) {
        if ($q == null) {
            $q  = $this->createQuery();
        }

        $q->addWhere('deleted_at is null');

        return $q;
    }

    public function addStandardOrderBy(Doctrine_Query $q = null) {
        if ($q == null) {
            $q  = $this->createQuery();
        }

        $q->addOrderBy('collectionName');

        return $q;
    }

    public function addOrderByLastCreated(Doctrine_Query $q = null) {
      if ($q == null) {
            $q  = $this->createQuery();
        }

        $q->addOrderBy('created_at desc');

        return $q;
    }

    public function addUinStartRangeQuery($uin, Doctrine_Query $q = null) {
        if ($q == null) {
            $q  = $this->createQuery();
        }

        $q->addWhere('uin >= ?',$uin);

        return $q;
    }

    public function addUinEndRangeQuery($uin, Doctrine_Query $q = null) {
        if ($q == null) {
            $q  = $this->createQuery();
        }

        $q->addWhere('uin <= ?',$uin);

        return $q;
    }

    public function getCollectionListQuery(Doctrine_Query $q = null) {
        if ($q == null) {
            $q  = $this->createQuery();

        }

        $q = $this->addNonArchivedQuery($q);
        $q->addOrderBy('collectionName');

        return $q;
    }


    public function addCollectionsModifiedAfterDate($lastUpdated, Doctrine_Query $q) {
        if ($q == null) {
            $q  = $this->createQuery();
        }
        $q->addWhere('updated_At > ?', $lastUpdated);

        return $q;
    }
    
    /**
     * Finds all Collections that have a CollectionRelation with the
     * designated type
     *
     * NOTE: does not search relating collections - i.e. the search is one way
     *
     * @param array $relationIdentifiers
     * @param Doctrine_Query $q
     * @return <type>
     */
    public function addSearchByHasRelationTypesQuery(array $relationIdentifiers, Doctrine_Query $q = null) {
        if ($q == null) {
            $q  = $this->createQuery();
        }

        $q->innerJoin('CollectionItem.CollectionRelations cr');
        $q->innerJoin('cr.RelationType rt');
        $q->andWhereIn('rt.typeValue', $relationIdentifiers);

        return $q;
    }

    /**
     * Find all collections matching the supplied collectionTypeIdentifiers
     * (array)
     *
     * @param array $collectionTypeIdentifier
     * @param Doctrine_Query $q
     * @return <type>
     */
    public function addSearchByCollectionTypeQuery(array $collectionTypeIdentifier, Doctrine_Query $q = null) {
        if ($q == null) {
            $q  = $this->createQuery();
        }

        $q->innerJoin('CollectionItem.CollectionType ct');
        $q->andWhereIn('ct.typeValue',$collectionTypeIdentifier);

        return $q;
    }

    public function addSearchByMinimumVisibilityLevel($visibilityLevel, Doctrine_Query $q = null) {
        if ($q == null) {
            $q  = $this->createQuery();
        }

        $q->innerJoin('CollectionItem.VisibilityLevel vl');
        $q->andWhere('vl.typeValue >= :visibilityLevel',array('visibilityLevel' => $visibilityLevel));

        return $q;
    }

    public function getCollectionsByNamePartQuery($namePart, Doctrine_Query $q = null) {
        if ($q == null) {
            $q  = $this->createQuery();
        }
        $q = $this->addNonArchivedQuery($q);
        $q->addWhere('UPPER(CollectionName) like :colName', array ('colName' => '%'.strtoupper($namePart).'%'));
        return $q;
    }

    public function getCollectionsByTagNameQuery($tagName, Doctrine_Query $q = null) {
        if ($q == null) {
            $q  = $this->createQuery();
        }
        $q = $this->getCollectionListQuery($q);
        $q->innerJoin('CollectionItem.CollectionTags ct');
        $q->innerJoin('ct.SubjectTag st');
        $q->addWhere('UPPER(st.typeName) = ?',strtoupper($tagName));

        return $q;
    }

    public function getCollectionsByTagNamesQuery($tagNames) {
        $q  = $this->createQuery();
        $q = $this->getCollectionListQuery($q);
        foreach ($tagNames as $index => $tagName) {
            $q->andWhere('EXISTS (SELECT s'.$index.'.typename FROM SubjectTag s'.$index.' '.
                    'INNER JOIN s'.$index.'.CollectionTag ct'.$index.' '.
                    'WHERE ct'.$index.'.collectionuin = CollectionItem.uin AND UPPER(s'.$index.'.typename) = ? )',strtoupper($tagName));
        }
        return $q;
    }

    public function getCollectionsByUins(array $uins, Doctrine_Query $q = null) {
        if (count($uins) > 0 ) {
            if ($q == null) {
                $q = $this->createQuery();
            }
            $q = $this->getCollectionListQuery($q);
            $q->andWhereIn('uin', $uins);
        }
        return $q;
    }



}